package ch.exm.storm.query.hibernate;

import ch.exm.storm.conditions.arguments.Argument;
import ch.exm.storm.conditions.arguments.EvaluatedArgument;
import ch.exm.storm.query.relational.AbstractRelationalQuery;
import ch.exm.storm.query.selection.EvaluatedRelationalSelection;

public class HibernateQuery extends AbstractRelationalQuery {

	private HibernateConfiguration configuration;
	
	private SessionProvider sessionProvider;
	
	HibernateQuery(HibernateConfiguration configuration, SessionProvider sessionProvider) {
		this.configuration = configuration;
		this.sessionProvider = sessionProvider;
	}
	
	@Override
	public HibernateQueryPlan getQueryPlan() {
		return (HibernateQueryPlan)super.getQueryPlan();
	}
	
	protected HibernateQueryPlan createRelationalQueryPlan() {
		return new HibernateQueryPlan(sessionProvider);
	}
	
	public EvaluatedArgument evaluateArgument(Argument argument) {
		EvaluatedArgument evaluatedArgument = configuration.evaluateArgument(this, argument);
		if (!evaluatedArgument.isFullyEvaluated()) nonFullyEvaluatedArguments.add(evaluatedArgument);
		return evaluatedArgument;
	}
	
	String addSelectedArgument(Argument argument) {
		String alias = argument.getRootReference();
		if (!aliasMap.containsKey(alias)) aliasMap.put(alias, argument.getRootArgumentClass());
		return alias;
	}
	
	@Override
	protected String getSelectStatement() {
		if (selection == null) return "";

		EvaluatedRelationalSelection evaluatedSelection = configuration.evaluateSelection(this, selection);
		if (!nonFullyEvaluatedArguments.isEmpty()) {
			getQueryPlan().setPostSelection(evaluatedSelection);
			return "";
		}
		
		String evaluated = evaluatedSelection.getSelectionStatement();
		if (!evaluatedSelection.isFullyEvaluated()) {
			getQueryPlan().setPostSelection(evaluatedSelection);
		}
		
		if (evaluated == null) return "";

		StringBuilder select = new StringBuilder("select ");
		select.append(evaluated);

		return select.append(" ").toString();
	}
	
	@Override
	protected String getFromStatement() {
		StringBuilder from = new StringBuilder("from ");
		boolean first = true;
		for (String alias : aliasMap.keySet()) {
			if (first) first = false;
			else from.append(", ");
			Class<?> clazz = aliasMap.get(alias);
			from.append(clazz.getName()).append(" ").append(alias);
		}
		if (from.length() > 0) from.append(" ");
		return from.toString();
	}
	
	@Override
	protected String getWhereStatement() {
		String whereStatement = conditions.getWhereStatement();
		return whereStatement == null || whereStatement.length() == 0 ? "" : "where " + whereStatement;
	}
}
